feat(platform-objects): secure-by-default posture for sensitive system objects (ADR-0066 ④)#2691
Merged
Merged
Conversation
…m objects (ADR-0066 ④)
The platform's raw secret/credential stores no longer ride the wildcard `'*'`
permission grant. `sys_secret`, `sys_jwks`, `sys_verification`,
`sys_oauth_access_token`, `sys_oauth_refresh_token`, and `sys_device_code`
declare `access: { default: 'private' }` — an ordinary member's generic
data-layer access gets 403; platform admins retain access via the
posture-gated viewAllRecords/modifyAllRecords superuser bypass.
Every runtime consumer is unaffected (verified per reader): better-auth reads
via its adapter (system context), `engine.resolveSecret` reads at driver
level, SettingsService / the datasource secret-binder read principal-less
(middleware falls open for internal calls), API-key auth reads isSystem.
- `sys_scim_provider` gains `requiredPermissions: ['manage_platform_settings']`
(D3 capability gate), mirroring its sibling `sys_sso_provider`.
- Setup nav `nav_jwks` is capability-gated like `nav_api_keys` so non-admins
don't see a menu entry that can only 403.
- Member self-service objects (sys_session, sys_api_key,
sys_oauth_application, sys_two_factor) deliberately keep the public
posture — the Account app reads them as the member; row scoping is their
guard. A test asserts this exclusion too.
- Pinned against regression: platform-objects.test.ts posture suite + the
ADR-0056 D10 conformance-matrix row `secure-by-default-posture`.
Tests: platform-objects 71, plugin-auth 230, dogfood conformance +
anonymous-deny + two-doors e2e, service-settings 129, service-datasource 93 —
all green; full turbo build green.
Refs #2561
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0187GeNqezxV6g5jiLiggfbt
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 2 package(s): 3 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
…ADR-0066 ④) The Advanced table listed Verifications and Device Codes, but those nav entries were deliberately removed (sensitive ephemeral secrets — not browsable; see setup-nav.contributions.ts). Also document that nav_jwks is capability-gated and sys_jwks is private-posture. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0187GeNqezxV6g5jiLiggfbt
18 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Lands the system-object slice of ADR-0066 ④ (secure-by-default rollout) from the authorization gap map (umbrella #2561). The D2
access: { default: 'private' }primitive has been enforced since #2690's predecessors — but no production object used it: the platform's raw secret/credential stores were still covered bymember_default's wildcard'*': allowRead. This PR flips the clearly-sensitive, flip-safe ones.Change
6 objects →
access: { default: 'private' }sys_secretsys_jwkssys_verificationsys_oauth_access_tokensys_oauth_refresh_tokensys_device_codeAn ordinary member's generic data-layer access now 403s; platform admins retain access via the posture-gated
viewAllRecords/modifyAllRecordssuperuser bypass.Flip-safety — every runtime consumer verified
isSystem: true→ middleware short-circuits; auth flows unaffected.engine.resolveSecretreadssys_secretat driver level (below the middleware).core/security/api-key.ts) reads withisSystem: true.Deliberately excluded (member self-service)
sys_session,sys_api_key,sys_oauth_application,sys_two_factorkeep the public posture: the Account app ("My Sessions" / "My API Keys" / "My Apps" / 2FA "My Enrollment") reads them through the generic data layer as the member — flipping them would break self-service. Row scoping (owner/tenant RLS +_selfcarve-outs) remains their guard. A test asserts the exclusion so it's a documented decision, not an oversight.Also
sys_scim_provider(SCIM bearer-token config) gainsrequiredPermissions: ['manage_platform_settings']— mirrors its siblingsys_sso_provider's D3 gate.nav_jwksis capability-gated likenav_api_keys(UX: non-admins no longer see a menu entry that can only 403).Regression pinning
platform-objects.test.ts— "secure-by-default posture" suite asserts each flip and the self-service exclusions.secure-by-default-posture(dropping the flag from a secret store fails CI, not review).content/docs/permissions/authorization.mdxupdated: system-object slice landed; still open = Studio posture surfacing (objectui) and the explicit-publicreference-data convention (no such objects ship in framework today).Tests / verification
platform-objects: 71 passed (incl. new posture suite)plugin-auth: 230 passed (auth flows unaffected by the flips)showcase-anonymous-deny+two-doors-permissione2e (real kernel boot + login) 8 passedservice-settings129 +service-datasource93 passed (thesys_secretconsumers)turbo buildgreenRefs #2561
🤖 Generated with Claude Code
https://claude.ai/code/session_0187GeNqezxV6g5jiLiggfbt
Generated by Claude Code